﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Engine.Sgml.Matching {
    internal sealed class CapturesIterator : IEnumerator<Capture> {
        private Match root;
        private Match match;
        private int captureIndex;

        public Capture Current {
            get {
                if (captureIndex < 0)
                    return default(Capture);
                else
                    return match.Captures[captureIndex];
                }
            }

        public void Dispose() { }

        object System.Collections.IEnumerator.Current {
            get { return Current; }
            }

        public bool MoveNext() {
            if (match == null)
                throw new InvalidOperationException();
            if (captureIndex < 0 && match.Captures.Count > 0) {
                captureIndex = 0;
                return true;
                }
            if (Current.Entity.IsModelMatch && Current.Entity.Match.Captures.Count > 0) {
                match = Current.Entity.Match;
                captureIndex = 0;
                return true;
                }
            else if (++captureIndex < match.Captures.Count)
                return true;
            else {
                Match m = match;
                Match p = m.Parent;
                while (p != null) {
                    if (p == root)
                        return MoveNext(root, m);
                    else if (MoveNext(p, m))
                        return true;
                    m = p;
                    p = p.Parent;
                    }
                return false;
                }
            }

        private bool MoveNext(Match parent, Match inner) {
            for (int i = 0; i < parent.Captures.Count; i++) {
                if (object.ReferenceEquals(parent.Captures[i].Entity.Match, inner)) {
                    if (++i < parent.Captures.Count) {
                        this.match = parent;
                        this.captureIndex = i;
                        return true;
                        }
                    else
                        break;
                    }
                }
            captureIndex = -1;
            return false;
            }

        public void Reset() {
            if (match == null)
                throw new InvalidOperationException();
            captureIndex = -1;
            this.match = root;
            }

        public void Reset(Match match) {
            Guard.ArgumentNotNull(match, "match");
            this.root = match;
            this.match = match;
            this.captureIndex = -1;
            }
        }
    }
